perm filename MACHIN.DOC[NEW,AIL] blob
sn#408299 filedate 1979-01-08 generic text, type T, neo UTF8
SAIL and PDP10 Machine Language January 26, 1976
Table of Contents
Table of Contents
Table of Contents
Table of Contents
Chapter Page
Section
List of Figures . . . . . . . . . . . . . . iii
I. SAIL and Machine Language . . . . . . . . . . . . . . 1
II. The PDP-10 Machine Language . . . . . . . . . . . . . 2
II.0 Introduction . . . . . . . . . . . . . . . 2
II.1 Memory Architecture of the PDP-10 . . . . . . . . . 2
II.2 A Note on Number Systems . . . . . . . . . . . . 4
II.3 The Word . . . . . . . . . . . . . . . 5
II.4 Number Representation . . . . . . . . . . . . . 6
II.5 Instruction Words . . . . . . . . . . . . . . 7
II.6 Using DDT . . . . . . . . . . . . . . . 9
II.7 Calculation of the Effective Address of an
Instruction . . . . . . . . . . . . . . 11
II.8 Immediate and Direct Instructions . . . . . . . . 13
II.9 Arithmetic Instructions . . . . . . . . . . . 14
II.10 Instructions Which Change the Program Counter . . . . 14
III. Some Examples of SAIL Code . . . . . . . . . . . . 17
III.0 IF ... THEN . . . . . . . . . . . . . . 17
III.1 DO, WHILE, and FOR Loops . . . . . . . . . . . 18
III.2 Pushdown Instructions . . . . . . . . . . . . 19
i
SAIL and PDP10 Machine Language January 26, 1976
III.3 SAIL Subroutine Calling Conventions . . . . . . . 21
III.4 Byte Pointers and SAIL Strings . . . . . . . . . 23
III.5 Strings in Procedure Calls . . . . . . . . . . 28
III.6 Array Implementation . . . . . . . . . . . . 29
Appendix I
Machine Instructions Commonly Used by SAIL . . . . . . . 32
ii
SAIL and PDP10 Machine Language January 26, 1976
List of Figures
List of Figures
List of Figures
List of Figures
1. Overall Hardware Configuration . . . . . . . . . . . . . 3
2. Representation of Decimal Digets . . . . . . . . . . . . 5
3. A Word . . . . . . . . . . . . . . . 5
4. The Fields of an Instruction Word . . . . . . . . . . . . 7
iii
SAIL and PDP10 Machine Language January 26, 1976
Chapter I
Chapter I
Chapter I
Chapter I
SAIL and Machine Language
SAIL and Machine Language
SAIL and Machine Language
SAIL and Machine Language
The purpose of these notes is to discuss the relationship of the
SAIL language with the PDP-10 computer and its machine language. It is
intended to give a better sense of the semantics of SAIL in terms of the
PDP-10, thus assisting in debugging, and also to provide some help in
interfacing machine language to the SAIL system.
Chapter II discusses features of the PDP-10 relevant to SAIL,
including some examples of SAIL compiled code and data structures.
1
SAIL and PDP10 Machine Language January 26, 1976
Chapter II
Chapter II
Chapter II
Chapter II
The PDP-10 Machine Language
The PDP-10 Machine Language
The PDP-10 Machine Language
The PDP-10 Machine Language
II.0 Introduction
Introduction
Introduction
Introduction
What is machine language? On our system this term could be used in
three senses:
1) The architecture of the central processing unit (CPU).
2) A machine language assembler, which creates and loads
programs. It is usually quite complicated. There are two main
machine language assemblers used at IMSSS: FAIL and MACRO (1).
3) An interpreter, such as DDT. Since DDT is highly
interactive it is an excellent starting point for learning more
about CPU architecture, assembly language, and debugging compiled
code.
II.1 Memory Architecture of the PDP-10
Memory Architecture of the PDP-10
Memory Architecture of the PDP-10
Memory Architecture of the PDP-10
Figure 1 gives a picture of the overall hardware configuration of
the PDP-10.
------------
(1) There is also a third available, called MIDAS but it is not
maintained at IMSSS.
2
SAIL and PDP10 Machine Language January 26, 1976
IMLAC ... IMLAC
| |
| |
| |
HIGH-SPEED LINES
|
|
|
----------- |
| | |
| MAGTAPE | |
| | ------------------------------------
----------- | |
| | ----------- |
-------- | CPU | ACCUMU- | | --------
| | | | LATORS | | | |
| DISK |-----| (KI-10) ----------- |----| DRUM |
| | | ----------- | | |
-------- | | "Hidden | | --------
| | | Memory" | |
----------- | ----------- |
| | | |
| DECTAPE | ------------------------------------
| | | |
----------- | |
| |
| |
| |
| |
MULTIPLEXING LINES ----------
| | | | |
| | | | MEMORY |
TTY's DM's TEC'S | (256K) |
| |
----------
Figure 1. Overall Hardware Configuration
Some Remarks:
1) The accumulators may be thought of as high-speed memory.
2) The "hidden memory" is available to the CPU, but is
transparent to the user.
3) The drum is used in "swapping" and "paging" operations so
3
SAIL and PDP10 Machine Language January 26, 1976
it serves as a somewhat slower memory. The drum at IMSSS has a
capacity of about three million 36-bit words. If this isn't
enough, swapping will use the disk, which is considerable slower.
4) The IMSSS memory unit has a capacity of 256K words, where
10
K = 2 = 1024 (decimal).
5) Magtape and Dectape can be thought of as very (!) slow
forms of memory.
6) The multiplexing lines for TTY's, TEC's, and DM's avoid
having the CPU look at each terminal separately to see if there is
any input from it.
II.2 A Note on Number Systems
A Note on Number Systems
A Note on Number Systems
A Note on Number Systems
Most readers will already be familiar with representation of
numbers in various "bases", e.g. the familiar decimal (base 10) notation
used everywhere except around computers, or binary notation using just 0's
and 1's. The technical term preferred by many computer scientists for
number base is radix. Thus when balancing a checkbook, you are using radix
radix
radix
radix
10 notation for numbers. There are two others which are convenient when
dealing with our system: radix 2 (binary) and radix 8 (octal).
It can be somewhat confusing at first to keep track of which radix
is being used in a given context. With experience, it will become easier
to keep things straight. For the time being I will try to be careful to
make it clear what radix is currently being used. There are two common
conventions for indicating the radix:
1) A (decimal) subscript, e.g. 27∪10∩.
2) For radix 8, an apostrophe precedes the string of numerals,
e.g. the octal representation of 66 (decimal) is '102. The
apostrophe convention should already be familiar since it is
generally used when specifying the octal representation of an ASCII
character.
Context usually makes it clear when binary notation is being used.
In this section the apostrophe convention will be used to indicate radix 8
and, in text at least, radix 10 should be assumed. However, in later
chapters explicit mention will be made of the radix only where there seems
a genuine danger of confusion. The next figure gives the decimal digets
and their binary and octal representations.
4
SAIL and PDP10 Machine Language January 26, 1976
decimal binary octal
------------------------
0 0 0
1 1 1
2 10 2
3 11 3
4 100 4
5 101 5
6 110 6
7 111 7
8 1000 10
9 1001 11
Figure 2. Representation of Decimal Digets
II.3 The Word
The Word
The Word
The Word
The basic unit of information is called a word; in the PDP-10 a
word
word
word
word consists of a string of 36 binary digits (either 0 or 1). (In the
hardware there are 37, with the extra bit used to maintain parity; the user
never sees the parity bit.)
II.3.1 Nomenclature
Nomenclature
Nomenclature
Nomenclature
Regarding a word as a string of 36 binary digits or bits, the bits
bits
bits
bits
are numbered from left to right starting with 0 and ending with 35
(decimal):
-----------------------------------------------------------------------
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
-----------------------------------------------------------------------
0 18 35
Figure 3. A Word
Sometimes bits are also counted from the right. In this case, they
are grouped into triples (handy when thinking of a word as an octal
number). The rightmost bit is called "the 1 bit", bit 34 is "the 2 bit",
33 is the "the 4 bit", 32 is "the 10 bit", 31 is "the 20 bit", 30 is "the
40 bit" and so forth. It is often convenient to think of a word as divided
into two half words of 18 bits each. In this case the rightmost bit of the
left half word (bit 17) is also called the 1 bit (of the left half word).
5
SAIL and PDP10 Machine Language January 26, 1976
Thus when context makes it clear that we are talking about the left half of
a word, bit 13 might be called the 20 bit.
Since the rightmost digets of the number are the least significant
(e.g. in terms of accuracy of a measurement) the rightmost bits of a word
are called the least significant bits. These bits are also called the low
least significant bits low
least significant bits low
least significant bits low
order bits, and bit 35 is THE low order bit.
order bits low order bit
order bits low order bit
order bits low order bit
Finally, a byte is any consecutive subpart of a word which is of
byte
byte
byte
one to thirty-five bits in length.
II.3.2 Interpreting a Word
Interpreting a Word
Interpreting a Word
Interpreting a Word
There are four ways of interpreting a word that will be of interest
to us:
1) Simply as a piece or pieces of stored information or data.
For example, for reasons unknown one could use a single word to
store the following information: bits 0-2 encode the day of the
week, 3-6 the month, 4-11 the date, 12-18 the year (to be
interpreted as the last two decimal digets of the year), 19-23 the
hour (24 hour clock), 24-29 the hour (minutes), and 30-35 might
give the number of one of 64 possible "canned" messages.
2) As ASCII text. Since there are '200 different ASCII
characters numbered from '0 thru '177, 7 bits are required to
represent one ASCII character. But there are 36 bits in a word, so
it is possible to store 5 ASCII characters in a word, with one bit
left over. The convention used is that the low order bit (bit 35)
is ignored.
3) As a signed integer.
4) As a floating point (real) number.
5) And finally, a word can be interpreted as an instruction to
the CPU.
These last three will be discussed in more detail in the following
sections.
II.4 Number Representation
Number Representation
Number Representation
Number Representation
[A section on integers, floating point numbers, and a little
arithmetic.]
6
SAIL and PDP10 Machine Language January 26, 1976
II.5 Instruction Words
Instruction Words
Instruction Words
Instruction Words
One of the merits of the PDP-10 instruction set is that
"instruction words" have a very standard format.
II.5.1 Fields
Fields
Fields
Fields
When interpreted as an instruction, a word is divided into five
fields. The left half of the word contains the first four of these fields
fields
fields
fields
and the right half comprises the fifth.
Location Name Remarks
(by bit number)
------------------------------------------------------------------------
0 - 8 Opcode Field The bit pattern for
the instruction
9 - 12 Accumulator Field Address of an
accumulator
13 Indirect Address Bit For indirect addressing
(See below)
14 - 17 Index Register Field Used in calculating the
effective address (See
below)
18 - 35 Address Field
Figure 4. The Fields of an Instruction Word
Each location in memory represents a single word. Since we operate
under a timesharing monitor and in a paging environment, each user has a
virtual PDP-10 with its full memory at his command. (2) Each word in memory
has an (octal) address ranging from '0 to '777777.
NOTE: All memory locations will ALWAYS be referred to as octal
numbers, not decimal. In this chapter we will usually remind you of this
by using the "'" notation, but it will be dropped in subsequent chapters.
The first sixteen locations in memory ('0 - '17) are somewhat
------------
(2) And since it is possible to have several "forks" for the same job
it is possible to have several copies of memory to work with if need be.
7
SAIL and PDP10 Machine Language January 26, 1976
special. '0 - '17 are sometimes referred to as accumulators and '1 - '17
accumulators
accumulators
accumulators
as index registers. Their use will become apparent when we begin
index registers
index registers
index registers
discussing particular instructions. They are the "high speed" memory
referred to earlier, and most of the "work" of the computer is done by
altering the contents of registers.
We now discuss the five fields a bit more precisely.
The opcode field contains the number of the instruction to be
executed. Each number has a name, e.g., 254 is the JRST instruction.
The address field is used to store an address (i.e. a location in
memory) which will be used by the particular instruction.
The accumulator field contains the address of one of the sixteen
accumulators. Various instructions can use this information in different
ways. One typical use is as the destination for a word copied from
somewhere else in memory.
The indirect address bit is used in calculating the address
actually used by the instruction according to the procedure described
below.
The index register field is used to address one of the memory
locations '1-'17. If it is non-zero the contents of the addressed index
register are used as part of the calculation of the effective address of
the instruction. Note: In this case, "contents of the index register"
means the contents of the RIGHT half word only.
II.5.2 The Effective Address
The Effective Address
The Effective Address
The Effective Address
Although bits 18 - 35 comprise the address field, ALL of the
information contained in bits 13 - 35 is used to calculate the address used
by an instruction: In the following, let I be the contents of the indirect
address bit (bit 13), X be the CONTENTS of the index register specified in
the index register field (bits 14 - 17) (3), and let Y be the contents of
the address field (bits 18 - 35).
The address actually used by the instruction, called the effective
effective
effective
effective
address, is calculated by the following recursive procedure: Add X and Y.
address
address
address
(The result is, of course, an 18-bit binary number.) If I = 0, we are done.
But if I = 1, go to the address X+Y, look at bits 13 - 35 of the word
contained there, calculate a new X and Y, and then repeat the procedure
------------
(3) However, 0 is NEVER an index register -- if 0 occurs in the index
register field of an instruction, then there simply is no index register.
(4) Note that the process repeats until we find a word with I = 0.
8
SAIL and PDP10 Machine Language January 26, 1976
(4). The address X+Y of this final word is the one used by the
instruction. In the PDP-10 Reference Manual this final address is denoted
by E.
The value of E is ALWAYS calculated just as above. In particular,
even if the instruction in question does not require an address, E is
calculated and this value is used by the instruction in the appropriate
fashion. In other words, whenever the indirect address bit is 1, X+Y is
interpreted as an address regardless of the nature of the instruction.
II.6 Using DDT
Using DDT
Using DDT
Using DDT
With the preliminaries out of the way, we can begin discussing DDT
(5). To use DDT as an interpreter, simply run DDT as you would any other
program on <SUBSYS>:
@DD<CR>
WARNING: When you intend to use DDT as an interpreter it is very
important that you do a RESET first to flush any program resident in your
core image. If you don't, things will get a bit confusing and should you
exit and try to continue the system will attempt to execute your (now
probably horribly smashed) copy of the program you were last using.
DDT greets you in a very unassuming fashion by returning two
carriage-returns. No message is printed, but once the carriage returns
have been typed DDT is ready to accept commands.
The first command to try is "n/", where n is a non-negative octal
integer not greater than '777777. The effect of this command is two-fold:
First, DDT will print out the contents of address n (either as a symbolic
instruction, or as an octal number, depending). Secondly, the address is
opened for writing, i.e. you can alter the contents of address n. A
carriage return closes the address. So to deposit the number 12 at address
100, you would type
"100/"
and DDT would type out the current contents of address '100, or, in case
your are starting with a "clean" core image, DDT will reply with a question
mark which is its way of telling you that this address has not yet been
used. Then type
------------
(5) Dynamic Debugging Technique.
9
SAIL and PDP10 Machine Language January 26, 1976
12<CR>.
If you try "100/" now, DDT will print out "12".
For the simple symbolic instructions that we will look at first, we
need not worry about effective addresses: What you see is what you get.
For the moment we can consider an instruction word to be made up of three
parts, namely an opcode, an accumulator field, and an address field.
These will print out in the form
OPCODE AC (6),Address
E.g.
MOVE 1,100
DDT will also execute instructions which are given in the above
format. Simply type the instruction followed by "$X", where "$" means hit
the ALT MODE (or ESC or ENTER) key. "$X" tells DDT to execute the command
you just typed, and hitting the ALT MODE key will actually echo on your
terminal as a "$". In case you mistype an instruction, use the DELETE key.
It deletes the ENTIRE line you have typed, and echos at the terminal as an
"XXX<CR>" sequence.
We finish with a discussion of two instructions, MOVE and MOVEM.
The MOVE instruction is of the form MOVE AC,ADDRESS. It's effect
is to copy the contents of ADDRESS into accumulator AC. Thus if address
100 contained 12 and you typed "MOVE 1,100$X" to DDT, then accumulator 1
(which is at address 1 also) would now then contain "12".
MOVEM AC,ADDRESS is the reverse of MOVE: it will take the contents
of accumulator AC and copy it to ADDRESS.
Exercises
Exercises
Exercises
Exercises
1) Read the first section in the PDP-10 System Reference
Manual, which is the first section in the PDP-10 Reference
Handbook.
2) A word could be thought of as a sequence of thirty-six
on/off switches with each switch corresponding to a bit and the
"on" position represented by a 1. Then we can talk about turning
on certain bits. This is often used in the JSYS manual and is a
convenience when a single word is used to encode which of a long
list of options are desired--turning on the appropriate bit selects
------------
(6) I.e. accumulator field
10
SAIL and PDP10 Machine Language January 26, 1976
the option or sets a flag. But since it is quite inconvenient to
type out a string of thirty-six 0's and 1's, radix 8 notation is
generally used so that "only" twelve digets are needed. Question:
What is the (octal) representation of a word in which the 2 bit, 10
bit, 4000 bit and 200000 bit of the left half word are turned on?
3) What is the representation of each of the following
integers as a 36-bit word: 0,2,106,-1,106? What is the greatest
positive integer expressible as a word? The greatest negative
integer?
4) What is the representation of each of the following REAL
numbers: 0., 1.0,3.14159,106.,-106?
5) Why isn't accumulator '0 used as an index register?
6) Try the following commands in DDT: MOVE, MOVEM, ADD, ADDM,
SUB, SUBM.
II.7 Calculation of the Effective Address of an Instruction
Calculation of the Effective Address of an Instruction
Calculation of the Effective Address of an Instruction
Calculation of the Effective Address of an Instruction
Since all (user) instructions have the same format, the PDP 10 is a
nice machine to deal with. An important concept that we need is the notion
of the effective address of an instruction.
effective address
effective address
effective address
The accumulators '1 - '17 are sometimes also called "INDEX
REGISTERS", and can be used to help determine the effective address of an
instruction. Note that AC 0 is not on the above list -- if it were, the
contents of 0 would always be used to calculate the effective address of
any instruction which did not index one of the other AC's!!!
We saw in the last lecture that one form of an instruction was like
MOVE AC,100. We now look at two other forms. The first one includes
reference to an index register: MOVE AC,100(1) for example. In this case
the effective address is calculated by adding the CONTENTS of register 1 to
100.
Bit 13 of an instruction is called the indirect bit. Ordinarily
this bit is off. If it is on, we write an "@" sign in the instruction, as
in
MOVE AC,@100
The "@" causes the indirect address bit to be turned on, with the result
that the instead of moving the contents of 100 into AC, the contents of 100
will be taken to be an address, and (provided bit 13 of that address is
11
SAIL and PDP10 Machine Language January 26, 1976
OFF) the contents of that address will be moved to AC. Some examples
should help to clarify this.
Suppose the value of AC1 is 10, the value of location 100 is 50,
the value of 50 is 5, the value of 60 is 15, and the value of 110 is 60.
Then after executing Move 2,100 2 will contain 50. After MOVE 2,100(1) it
will be 15, after MOVE 2,@100 it will be 5, and after MOVE 2,@100(1) it
will be 15. Let's look at the last one closer. By adding the contents of
AC1 to 100 we get 110. The contents of 110 is 60. But indirect addressing
is in effect, so 60 is taken as an address rather than a value, so looking
at 60 we see that it contains 15. But if we changed the value of 60 to
20000015, or 20,,15 in half-word notation as DDT would usually display it,
then the indirect address bit of 60 would be "ON" as you can check for
yourself. If we then did MOVE 2,@100(1), the value of 2 would be 0. Why?
We obtain 60 as our second "intermediate" address. But its indirect bit is
"ON" so we have to continue calculating the address, which gives us 15 as
our next address. But we assume 15 contains 0, so its indirect bit is off,
and we move its contents to AC2.
REMARKS: i) DDT will let you write something like MOVE 2,100(@)1
and it will try to execute it. But the results will NOT be what you
expect. (E.g. if you are now in DDT and have followed through the above
sequence, put, say 7 into location 15 and 10 into location 10. Try MOVE
2,100(@10). See what 2 contains.) ii) More importantly, it is legal to
write an instruction like MOVE 100. This is taken to be the same as MOVE
0,100. And MOVE would be MOVE 0,0. iii) Note that if location 100
contained the instruction MOVE 1,@100, it could not be executed and the job
would "hang" -- The CPU is going to insist on calculating an effective
address (this is always done regard-less of whether it is used by the
instruction or not!!). But when it tries to do so it will loop. And there
you will sit!!
In practice in SAIL-compiled code, indirect addressing is not used
especially often, the main use being for REFERENCE parameters to
procedures. And the most frequent use of indexing is in connection with
arrays.
A location in memory (and this includes the accumulators) can be
given a symbolic name or LABEL. When we are using ONLY the (octal)
addresses of words in memory we speak of ABSOLUTE ADDRESSING, and when we
are allowed to use labels we speak of symbolic addressing. To assign a
label to an address you can open that address for writing using "/" and
then type the label (up to six characters) followed by a ":". DDT will
answer by moving the cursor (on a DPY) two spaces. This will not change
the contents of that address, though if you wish you can insert a new value
at this time since the address is still open for writing. A <CR> will, as
usual, close the word for writing. Suppose you called location 100 FOOBAZ.
Typing "FOOBAZ/" to DDT will now have exactly the same effect as typing
"100/", executing MOVE 1,FOOBAZ(2) will have the same effect as executing
MOVE 1,100(1) and so forth.
12
SAIL and PDP10 Machine Language January 26, 1976
A linefeed (<LF>) typed to DDT in place of a <CR> when you have an
address open for writing will take the following actions: i) close the
current location just like a <CR> and ii) open the next address for writing
(just like a /).
A "↑" works just like a <LF> except that it opens the previous
address for writing rather than the following (i.e. higher-numbered)
address.
One-dimensional arrays are easily constructed. To do so, you can
open an address, say 100, for writing and then store the first element of
the array there, the next element in the following location, and so on.
Try the following. Note: the periods after the integers tell DDT to take
those integers as being decimal rather than octal!
2/ J: <CR>
100/ A: 2. <LF>
A+1/ 4. <LF>
A+2/ 6. <LF>
A+3/ 8. <LF>
A+4/ 10. <CR>
200/ I: 3 <CR>
Now try executing the following two instructions and see what
happens: MOVE 1,I ; Don't forget to type $X to execute! MOVE J,A(1)
If you do this on-line you will have constructed an array A[0:4]
(about like the SAIL compiler would), and the two instructions you executed
would have had the same effect as "J ← A[I];" in SAIL, where a "I ← 3;" had
just been done.
We will look more closely at the array implementation in SAIL
later.
II.8 Immediate and Direct Instructions
Immediate and Direct Instructions
Immediate and Direct Instructions
Immediate and Direct Instructions
Once we have computed the effective address of an instruction there
are two ways of dealing with it. The way we have seen so far is called the
"direct" use, i.e. take the effective address and interpret it as an
address. However, the effective address can also be interpreted as a
number. In this case we speak of an "immediate" instruction.
13
SAIL and PDP10 Machine Language January 26, 1976
Many of the PDP-10 machine instructions contain the letter "I" for
"immediate". E.g. MOVEI 2,100 is an instruction. It will calculate the
effective address, 100 in this case, and move it, rather than its contents,
into AC2. Thus, if location 100 contains 506, then in this special case
both MOVE 1,100 and MOVEI 1,506 would deposit 506 in AC1. Again, note that
in an "immediate" instruction it is the EFFECTIVE ADDRESS rather than its
contents which is used in the instruction. Thus if 1 contains 10, then
MOVEI 2,506(1) would fetch 516 into AC2.
The SAIL statement
I ← J;
would compile as
MOVE 1,J
MOVEM 1,I
while
I ← 6;
would compile as
MOVEI 1,6
MOVEM 1,I
II.9 Arithmetic Instructions
Arithmetic Instructions
Arithmetic Instructions
Arithmetic Instructions
Four more simple instructions: MUL,DIV,IMUL, and IDIV for
multiplication and division. NOTE: In the case of IDIV (integer division)
an instruction like IDIV AC,Mem will put the integer portion of (contents
of AC divided by contents of Mem) into AC and the (integer) remainder into
AC + 1.
II.10 Instructions Which Change the Program Counter
Instructions Which Change the Program Counter
Instructions Which Change the Program Counter
Instructions Which Change the Program Counter
JRST (Jump and ReSTore flags):
JRST
JRST
JRST
An unconditional jump. Given in the form JRST Loc. It takes you
to the address with (symbolic) name Loc without further ado.
JUMPsuffix AC,Loc:
JUMPsuffix
JUMPsuffix
JUMPsuffix
14
SAIL and PDP10 Machine Language January 26, 1976
Comes in 8 varietics, depending upon the suffix. JUMP itself
(i.e., no suffix) is a no-op. The suffix list is:
no suffix No-op
E Equal
N Not equal
GE Greater than or Equal
G Greater than
L Less than
LE Less than or Equal
A Always
These 8 suffixes are important in the PDP10 instruction set, for they test
the value of the accumulator relative to 0 (e.g., is the value of the
accumulator Greater than or Equal to 0 means GE), using that test to decide
whether or not to perform some action. For example,
JUMPGE AC,LOC
jump to LOC and continue the program there if the contents of AC are
Greater or Equal to zero, and if not goes to the next instruction in
sequence.
Forgetting a suffix on the JUMP means JUMP never -- i.e., don't
JUMP. Using the A suffix -- JUMPA -- means JUMP always. The instruction
JUMPA ac,loc
is the same as JRST; JRST is faster.
SKIPsuffix AC,Loc:
SKIPsuffix
SKIPsuffix
SKIPsuffix
Takes same suffixes as JUMP (including A). SKIP and its variants
compare the contents of Loc with 0 and if the condition is satisfied skips
the next instruction. Thus,
SKIPA
JRST LOC1
JRST LOC2
simply skips over the JRST LOC1 instruction and executes JRST LOC2.
If the accumulator field of the SKIP instruction is not accumulator
0, then the contents of the effective address are moved into the
accumulator before the test. This instruction can be used to do both a
fetch and a test on a value at one time. The SAIL compiler does not use
this ability as often as it might.
CAMsuffix AC,Loc (Compare Ac with Memory):
CAMsuffix
CAMsuffix
CAMsuffix
15
SAIL and PDP10 Machine Language January 26, 1976
Compares contents of AC with contents of Loc and skip next instr if
condition satisfied. Same 8 suffixes as JUMP. Thus CAME AC,Loc will skip
the next instr in sequence if contents of AC is same as contents of Loc.
CAIsuffix AC,Loc (Compare Ac Immediate):
CAIsuffix
CAIsuffix
CAIsuffix
Like CAM, but is an immediate as opposed to a direct instruction.
Compares the contents of AC with Loc as opposed to the value of Loc.
16
SAIL and PDP10 Machine Language January 26, 1976
Chapter III
Chapter III
Chapter III
Chapter III
Some Examples of SAIL Code
Some Examples of SAIL Code
Some Examples of SAIL Code
Some Examples of SAIL Code
It is now possible to give some canonical code schemata for various
SAIL constructions. Doing this has three purposes: it gives a more
concrete characterization to the meaning of the SAIL construction; it makes
concrete the meaning of the PDP10 instructions by giving some examples; and
assists in debugging one's programs.
III.0 IF ... THEN
IF ... THEN
IF ... THEN
IF ... THEN
The statement
IF I GEQ 0 THEN S1
will compile
SKIPGE I ;test I GEQ 0
JRST BEYOND ;nope, its not
S2
.
.
.
BEYOND:
[Remark: In these and other examples, labels like BEYOND, LOOP, are made up
here for purposes of demonstration. In general, there will not be such
labels in your core image unless you have specifically used them as
identifiers in your program. Also, the S2... indicates that the code for
S2 (whatever it is) gets compiled at that point.
Also, these examples are only meant to be representative of the
actual code. In some cases, depending on context, the actual code may be
different. For example, if a value is known to be in a particular
accumulator, then the code to fetch it can be omitted.]
The statement
IF I LEQ 0 THEN S1 ELSE S2
becomes
SKIPLE I ;is I less than or equal to 0
JRST DOS2 ;no, go do S2
17
SAIL and PDP10 Machine Language January 26, 1976
S1
.
.
.
JRST BEYOND ;and jump around S2 code
DOS2: S2
.
.
.
BEYOND:
III.1 DO, WHILE, and FOR Loops
DO, WHILE, and FOR Loops
DO, WHILE, and FOR Loops
DO, WHILE, and FOR Loops
Several other ALGOL loops are given in the following:
WHILE I < 0 DO S1
compiles to
SKIPL I
JRST BEYOND
S1
.
.
.
BEYOND:
The statement
WHILE I < J DO S1
compiles to
MOVE AC,I ;fetch I into AC
CAML AC,J ;check whether I < J
JRST BEYOND
S1
.
.
.
BEYOND:
Notice, in comparing the above two examples, that the compiler selects the
most efficient test possible. In the first WHILE loop, the SKIPL
18
SAIL and PDP10 Machine Language January 26, 1976
instruction will test whether I is less than 0; in the second WHILE loop,
it is necessary to use two instruction, one to fetch a value into an
accumulator, the other to make the test. The compiler performs local
optimizations of this kind.
The FOR loop:
FOR I ← 1 STEP 1 UNTIL 10 DO S1
becomes
MOVEI AC,1 ;set initial value of I
LOOP: MOVEM AC,I
CAILE AC,12 ;10 decimal is 12 octal
S1
.
.
.
MOVE AC,I ;get I back into AC
AOJA AC,LOOP ;Add One to ac and Jump Always
BEYOND:
If the loop had been "STEP -1" then the last instruction would have been an
SOJA -- Subtract One from ac and Jump Always.
The DO...UNTIL:
DO S1 UNTIL J = 0;
compiles to
LOOP: S1
.
.
.
SKIPE J
JRST LOOP
"DO ... UNTIL" sometimes makes more elegant code than logically equivalent
"WHILE" statements, often allowing one fewer instruction.
III.2 Pushdown Instructions
Pushdown Instructions
Pushdown Instructions
Pushdown Instructions
There are four basic pushdown list instructions: PUSH, PUSHJ, POP,
and POPJ. They have the usual format, e.g. PUSH AC,Loc.
19
SAIL and PDP10 Machine Language January 26, 1976
The AC referenced in the instruction is a POINTER into the pushdown
stack. This pointer is a word, the left half of which contains the stack
counter and the address of the current top of the stack. The effective
address of the word which is at the top is the address of whatever word can
be thought of as being "stored" on the stack at that point. This probably
isn't very clear yet, but the following diagram and an example or two
should help to clarify.
Internally, a pushdown stack consists of the POINTER and some
consecutive section in memory, with the higher addresses being further down
on the stack:
------------ "bottom" of stack
------------
------------
------------
------------
------------ "top" of stack (the pointer "points" here)
------------
------------
------------
To use a pushdown stack you have to set it up. To do so you first
choose an accumulator. The usual choice here is traditionally 17, which is
usually called P for "pointer". SAIL uses accumulator 17 for its main
control stack, and it is called P. (There are two other registers in SAIL
that deal with push-down lists, SP (16) for strings, and RF (12) which is
another pointer into the same stack that P points to. P is loaded with a
word, the left half of which is the negative of an integer n, which will be
the maximal number of elements that can go on the stack. The right half is
the address of the initial top of the stack. (To begin with, it is also
the "bottom" of the stack.) That address Addr to address Addr + (n-1)
should now be regarded as being reserved for the pushdown stack. Normally,
these addresses shouldn't be altered except by use of the four instructions
mentioned earlier. Note: if you accidentally try to add too many elements
to the stack, it is called "pushdown overflow" and if you try to take too
many off (e.g. by trying to take something off before anything was put on
the stack), it is called "pushdown underflow".
Suppose WORD is a symbolic address containing -n,,start of stack
Then MOVE P,WORD (P as above) will set up AC 17 as a pushdown stack
which can contain up to n elements and which will run from location start
of stack to start of stack +(n-1). The SAIL stack comes already set up as
a stack by the SAIL runtime system.
Let I be a symbolic address. The instruction PUSH P,I has the
following effects after execution:
20
SAIL and PDP10 Machine Language January 26, 1976
1) P will now contain -n-1 (i.e. -(n+1),,start of
stack + 1.
2) The effective address calculated from the word at
start of stack + 1 will be a cell which contains the
contents of I.
Note: PUSH has side effects since the contents of start of stack +
1 have been changed.
POP is the compliment of PUSH. POP P,J will take the contents of
the current item on the stack and store it in location J. It also alters P
so that it points one element lower in the stack.
PUSHJ (PUSH and Jump): PUSHJ P,SUBR would put the return address on
the stack and jump to loc SUBR, continuing execution from there. PUSHJ
increments the pointer by 1 (i.e. changes P from -n,,addr to -n+1,,addr+1),
stores the current PC (Program Counter), i.e. current location on the top
of the stack, and continues at loc SUBR. It is used to execute a
subroutine then return and continue execution.
POPJ reads the top element of the stack (making the next one below
the new "top") and jumps to the location it specifies, continuing execution
of the program there. So PUSHJ lets us execute a subroutine; when finished
a POPJ will let us continue on where we were when the subroutine was
called.
III.3 SAIL Subroutine Calling Conventions
SAIL Subroutine Calling Conventions
SAIL Subroutine Calling Conventions
SAIL Subroutine Calling Conventions
NOTE: THIS SECTION IS A SLIGHT OVERSIMPLIFICATION!
We shall examine here a simplified version of the code for the
FACTORIAL function. The point of the example is to see how push-down lists
are used to implement SAIL subroutines.
SAIL subroutines calls work by pushing their arguments with the
PUSH instruction, in order, onto the P stack, and then calling the
subroutine with a PUSHJ. Values returned by a procedure are returned in
accumulator 1, which is called A.
Hence, suppose we have a procedure with the declaration:
INTEGER PROCEDURE F(INTEGER I,J); body of declaration
Then, the statement
I ← F(B,C)
21
SAIL and PDP10 Machine Language January 26, 1976
would compile as
PUSH P,B ;put B argument on the stack
PUSH P,C ;put C argument on the stack
PUSHJ P,F ;call function
MOVEM A,I ;store from ac A into cell I
Composed function calls are performed by sequences of
PUSHes and PUSHJ's. Thus,
I ← F(F(B,C),F(D,E))
would compile
PUSH P,B
PUSH P,C
PUSHJ P,F ;compute F(B,C)
PUSH P,A ;save result on stack
PUSH P,D
PUSH P,E
PUSHJ P,F ;compute F(D,E)
PUSH P,A ;stack now
;contains the two arguments
PUSHJ P,F ;compute F(F(B,C),F(D,E))
MOVEM A,I ;store result
Notice that the stack is adjusted correctly after this call -- i.e., the
stack pointer is the same at the end as it was at the beginning.
Otherwise, we would face serious problems. A common error in machine-
coding is getting the stack out of sync.
Let's look at a sample program, which will calculate a factorial
using the SAIL procedure:
RECURSIVE INTEGER PROCEDURE FACT(INTEGER I);
RETURN(IF I LEQ 0 THEN 1 ELSE FACT(I * FACT(I-1));
which might compile something like
FACT: SKIPG A,-1(P) ;aha -- argument is here
JRST RET1 ;I is LEQ 0
SUBI A,1 ;I - 1
PUSH P,A ;call
PUSHJ P,FACT ;FACT(I-1)
IMUL A,-1(P) ;I * FACT(I - 1)
RETURN: SUB P,[2000002] ;adjust the stack
JRST @2(P) ;and return
RET1: MOVEI A,1 ;RETURN(1)
JRST RETURN
22
SAIL and PDP10 Machine Language January 26, 1976
(Actually this code is more like a SAIL SIMPLE procedure than a RECURSIVE
one; this is the oversimplification.)
There are two important things about this procedure. First, the "-
1(P)" is a memory access using P (the stack pointer) as an index register.
It FETCHES THE LAST ARGUMENT TO THE PROCEDURE.
Consider the state of the stack coming into the procedure. It
looks like:
argument
return address --- P points here
Thus, (P) is the address of the return address, -1(P) fetches the last
argument, -2(p) fetches the next to the last argument, etc. (Value string
arguments are handled differently.) Whenever SAIL compiles code that refers
to -n(P), it is accessing an argument to a SIMPLE procedure.
Secondly, the two instructions at RETURN are for adjusting the
stack and returning. The first instruction removes two things from the
stack, by subtracting 2 from both sides of the stack. The JRST returns to
the next instruction in sequence. These two instructions are found at the
end of a typical SAIL procedure. If there are n (non-VALUE STRING)
arguments, then the number 2 becomes n+1 in these two instructions.
III.4 Byte Pointers and SAIL Strings
Byte Pointers and SAIL Strings
Byte Pointers and SAIL Strings
Byte Pointers and SAIL Strings
Strings are arbitrarily long lists of ASCII characters. SAIL
strings are actually a unit of 2 consecutive words known as a string
string
string
string
descriptor. The two words look like:
descriptor
descriptor
descriptor
S: XWD DYNAMIC,COUNT
BP
XWD means that DYNAMIC and COUNT are half words of the first word. COUNT
is the number of characters in the string; DYNAMIC is non-zero if the
string was created dynamically (e.g., by concatenating), zero if the string
is a constant string (which therefore does not require garbage collection).
BP is a PDP-10 byte pointer to the first character of the string.
We now discuss the notion of a byte-pointer. Sometimes we don't
want to use a full word or half word. For example, it takes 7 bits to
store one ASCII character and since there are 36 bits in a word, we can
store 7 ASCII characters (with a bit left over). There are also cases
where one wants to use other sizes of storage; 6, 8, 9, and 12 are all
common units.
23
SAIL and PDP10 Machine Language January 26, 1976
Any fraction of a word between 1 and 35 bits in length is called a
BYTE. In the following, we assume that we are not interested in bytes the
length of which can change from one byte to the next, but rather that we
know how long a byte will be. Given this, we need two pieces of
information to store or retrieve an arbitrary number of bytes, in addition
to the effective address of the word: i) the length of a byte and ii) where
in a word the "current" byte starts. This is enough information to allow
us to retrieve the current byte or to store another byte directly following
the current byte.
These two pieces of information are stored in a "byte pointer".
Internally, a byte pointer is a word in which bits 0-5 tell us the bit
number within the storage word at which the current byte starts (call these
bits P) and bits 6-11 tell us the size (i.e. length) of that byte (call
bits 6-11 S). Bits 13-35 perform their usual addressing functions, and the
effective address calculated from them is the address of the word
containing the current byte.
HOWEVER, P is not the bit number where the byte starts. To
facilitate the case where we have a consecutive series of bytes which
occupy more than one word, P is actually the number of "free" or unused
bits in a word. This makes it easy to modify P so that it points to the
next bit to the right: If S is the length of the current byte then P-S will
now point to the location of the next byte. Note that by assuming S to be
a constant, we can alter the pointer simply by performing the indicated
subtraction. Furthermore, if P-S < 0, we know that we don't have enough
room in the storage word to put another byte of length S. In this case, P
can be set to 0 and the right half of the byte pointer can be incremented
by 1 so that the effective address will now be the old effective address+1.
Thus, our byte pointer now will go looking in the next word to fetch a byte
or starting writing in the next word to store a byte. (This might seem
like a waste of space; suppose you wanted to store 8-bit bytes. Then you
would waste 4 bits in every word of byte storage. The KL-10 is rumored to
have some new instructions that make byte-stream storage possible.)
The following two diagrams, due to Scott Daniels, illustrate how a
byte pointer is constructed and how bytes are stored in a word:
24
SAIL and PDP10 Machine Language January 26, 1976
BYTE POINTER
POSITION | SIZE | |I| INDEX || WORD ADDRESS |
-----------|-----------|-|-|-------||-----------------------------------|
0|0|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|1||1|1|2|2|2|2|2|2|2|2|2|2|3|3|3|3|3|3|
0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7||8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|
-----------|-----------|-|-|-------||-----------------------------------|
(P) | (S) | | | || |
BYTE STORAGE
---------------------------------------|------------|------------|------|
| BYTE | NEXT BYTE | |
---------------------------------------|------------|------------|------|
<========35 - (S) - (P) BITS==========>|<=(S) BITS=>|<====(P) BITS=====>|
So, now that we have a scheme for keeping track of where our bytes
will go, what instructions do we have for doing byte manipulation? There
are five: (Assume below that the byte pointer has symbolic name BP.)
IBP BP -- This simply Incriments the Byte Pointer.
LDB AC,BP -- BP is the address of a word that is a byte pointer. The
byte pointed to is fetched into AC.
DPB AC,BP -- BP is the address of a word that is a byte pointer. The
contents of AC are deposited into that byte. (High-order bits
are removed from the contents of AC.)
ILDB AC,BP -- This instruction FIRST incriments the byte pointer, then
takes the same actions as LDB.
IDPB AC,BP -- First incriments the byte pointer, then does a DPB.
In SAIL, there is a function called POINT that will create a byte
pointer for you. The call is of the form BP←POINT(x,I,y) where BP and I
are declared to be integer. BP is the byte pointer, I is the address of
the (first) word containing the bytes, x is the number of bits in the byte
and y is an integer called the "last bit number". In case x is 7, you
might want to use 6 for y, provided you are using LDP to read the bytes.
Otherwise, and this holds regardless of the value of x, use -1 for y which
will insure that ILDB will do the right thing on its initial call. In FAIL
and MACRO there are pseudo-ops that create bytepointers at assembly time.
In SAIL, the following code (where TBP,NBP,TEXT, and NTEXT are
declared to be of type INTEGER) would transfer a 5 byte long 7-bit string
25
SAIL and PDP10 Machine Language January 26, 1976
stored left-justified in TEXT to NTEXT, where TEXT and NTEXT are declared
INTEGER, as well as the iteration variable I.
TBP ← POINT(7,TEXT,-1);
NBP ← POINT(7,NTEXT,-1);
FOR I ← 1 STEP 1 UNTIL 5 DO IDBP(ILDB(TBP),NBP);
What does the SAIL compiler do with a string declaration like
"STRING S;" ? This assembles as two instructions, say S which is of the
form
-------------------
|DYNAMIC | COUNT |
-------------------
and a second, say S+1, which is of the form
--------------------------
| BP pointer to 1st byte |
--------------------------
(The word DYNAMIC is non-zero just in case the string is dynamic.)
The SAIL function LENGTH(S) compiles as HRRZ AC,S (S as above).
Since this is the first time we have seen half-word instructions we digress
for a moment to introduce some of the more common ones:
The "H" is the mnemonic for "Half-word", "L" for "Left half (of a
word), "R" for "Right half", "Z" for all 0's, "O" for "all 1's, and I and M
as usual. Then some of the possibilities are:
FROM TO REST OF DESINATION
---- -- ------------------
R R Z I
H
L L O M
So, for example, HLRO AC,Loc would copy the left half of the word
at Loc (assuming bit 13 is off, of course) to the right half of AC, filling
the left half of AC with 1's.
A string assignment statement
S ← T;
where S and T are strings, might (but doesn't) compile as
MOVE AC,T
MOVEM AC,S
26
SAIL and PDP10 Machine Language January 26, 1976
MOVE AC,T+1
MOVEM AC,S+1
In fact, it compiles as
HRROI AC,T+1
POP AC,S+1
POP AC,S
which is one fewer instruction!! It works by making AC be a temporary
push-down pointer and then POPes the string, thus moving it. This is
another of the (relatively few) tricks that are used by the SAIL compiler.
Thus the SAIL code
I ← LENGTH(S)
is compiled as
HRRZ AC,S
MOVEM AC,I
LENGTH has the syntax of a subroutine, but no subroutine call is emitted
here. We say that LENGTH compiles open. The opposite is to compile
compiles open compile
compiles open compile
compiles open compile
closed.
closed
closed
closed
The SAIL LOP function for a string:
I ← LOP(S)
compiles as
HRRZ AC,S ; Store length of string in AC
JUMPE AC,DONE ; If length = 0, then finished
SUBI AC,1 ; Decrement the count
HRRZM AC,S ; and store in count field
ILDB AC,S+1 ; S+1 as above
DONE: MOVEM AC,I ;store
The SAIL statement If S = "A" THEN S1; (S a string, S1 a state-
ment) compiles as:
HRRZ AC,S
JUMPE AC,PLACE
MOVE AC,S+1
ILDB AC,AC
PLACE: CAIE AC,101
JRST BEYOND
|
27
SAIL and PDP10 Machine Language January 26, 1976
|(Code for S1)
|
BEYOND:
III.5 Strings in Procedure Calls
Strings in Procedure Calls
Strings in Procedure Calls
Strings in Procedure Calls
To cope with string procedures (especially those which are
recursive) and for garbage collection SAIL makes use of a string push-down
stack. AC 16 is used for this and is traditionally labeled "SP". Recall
the two words assembled by "STRING S;". These are what go onto the SP
stack when needed.
Example: Consider the following SAIL procedure
SIMPLE INTEGER PROCEDURE HOWMANY(STRING S; INTEGER CHAR)
BEGIN
INTEGER CNT,C;
CNT ← 0;
WHILE LENGTH(S) DO
BEGIN
C ← LOP(S);
IF C = CHAR THEN CNT ← CNT + 1;
END;
RETURN(CNT);
END;
A call on this procedure involves two arguments, 1 a value string S,
and the other an integer CHAR. The code for
I ← HOWMANY(T,C);
is therefore
PUSH SP,S
PUSH SP,S+1
PUSH P,C
PUSHJ P,HOWMANY
MOVEM A,I
String arguments are passed to procedures on the SP stack, and
likewise string results are returned on the SP stack. Thus, consider the
procedure:
STRING PROCEDURE UPPER(STRING S);
BEGIN
STRING U;
U ← NULL;
28
SAIL and PDP10 Machine Language January 26, 1976
WHILE (CHAR ← LOP(S)) DO
U ← U & (IF "a" LEQ C LEQ "z" THEN C -'40 ELSE C);
RETURN(U);
END;
The call
T ← UPPER(V);
compiles as
PUSH SP,V
PUSH SP,V+1
PUSHJ P,UPPER
POP SP,T+1
POP SP,T
Notice that the POPes are in reverse order than the PUSHes.
Exercise. Try compiling the above procedure for UPPER, identifying
Exercise
Exercise
Exercise
the WHILE loop, the LOP assignment, and the IF...THEN test within the
concatenation operator.
III.6 Array Implementation
Array Implementation
Array Implementation
Array Implementation
Arrays were discussed a bit previously. The simplest example of a
SAIL array is an outer block array (or an "OWN" array, which works the same
way) with one dimension and constant bounds beginning at 0, e.g. A[0:10],
which is declared of type integer. In this case the compiler can and will
allocate 11 contiguous words of memory for the array, assigning the label A
to A[0]. Thus A[n] can be found at A+n.
The code
J ← A[i]
is implemented as
MOVE AC,I
MOVE AC,A(AC)
MOVEM AC,J
The situation becomes a little more complex when the lower bound of
the array starts at a positive integer, as in A[1:10]. It is more complex
because if we assigned the label A to the location containing A[1], then
29
SAIL and PDP10 Machine Language January 26, 1976
A[n] would be found at location A+n-1 rather than at A+n. So the compiler
produces an offset in this case, by assigning the label A to the location
where A[0] would have been had the upper bound remained fixed where it is.
Thus knowing A, we know where A[n] is stored in memory. Of course code
like
MOVE AC,I
SUBI AC,1
MOVE AC,A(AC)
could have been produced, but it is more efficient to calculate A-1 once
and then produce code like
MOVE AC,I
MOVE AC,[A-1](AC)
The situation becomes rapidly more complex, when for example, an
array is declared within a procedure. If A is the array, then in this case
location A is used to store the beginning of the array. (Note that in such
cases the array is re-created each time the procedure is entered at run-
time and destroyed each time the procedure is exited. Thus, unless the
program is already quite large it is often better to declare an array in
the outer block of a SAIL program.) In front of a procedure in which an
array is declared one will find something like
PUSHJ P,ARMAK
MOVEM 1,A
where ARMAK is a SAIL function which takes care of the details of finding
space and so on. Since the "low segment" of the program will probably be
in a different state each time the procedure is entered, the array may be
stored in a different block of words upon each entry into the procedure.
Now consider how J ← A[I] will be implemented within a procedure:
MOVE AC,A
SUB AC,[1] ; get the offset correct
ADD AC,I ; when this is executed AC has the addr
MOVE AC,(AC)
MOVEM AC,J ; and move the value into J
Another degree of complexity is added when the array bounds are
variable, e.g. consider a procedure which includes m,n among its reference
variables and includes a declaration like ARRAY A[m:n];. In this case, A
will still point to the first element of the array, but above A (i.e. in
smaller numbered addresses) will be stored information on the array bounds
and so forth.
30
SAIL and PDP10 Machine Language January 26, 1976
In SAIL, unless an array is declared "SAFE", bounds checking is
performed. This would be implemented as something like the following for
an array A[1:10]
MOVE AC,J ; J is the bound being checked
CAIL AC,1
CAILE AC,10
ERR ;Special "UUO" to handle array error
MOVE AC,ORIGIN(AC)
MOVEM AC,I
Exercise Write a "machine language" version of
Exercise
Exercise
Exercise
BEGIN
INTEGER I,J,K;
INTEGER ARRAY A[1:10];
A[2] ← 4;
I ← A[2];
J ← 3;
I ← A[J];
FOR I ← 1 STEP 1 UNTIL 11 DO A[I] ← I;
END;
Then, compare it to the code produced by the SAIL compiler.
31
SAIL and PDP10 Machine Language January 26, 1976
Appendix I
Appendix I
Appendix I
Appendix I
Machine Instructions Commonly Used by SAIL
Machine Instructions Commonly Used by SAIL
Machine Instructions Commonly Used by SAIL
Machine Instructions Commonly Used by SAIL
The following machine instructions are commonly used by the SAIL
compiler.
MOVE
MOVEI
MOVEM
MOVSI
ADD
ADDI
ADDM
SUB
SUBM
IDIV
IDIVI
IMUL
IMULI
JRST
JUMPsuffix
SKIPsuffix
CAMsuffix
CAIsuffix
AOJA
SOJA
FADR
FSBR
FMPR
FDVR
HRRZ
HRRZM
HRRO
HRROI
PUSH
POP
PUSHJ
32
SAIL and PDP10 Machine Language January 26, 1976
POPJ
33